#ifndef _FILE_OFFSET_BITS
#define _FILE_OFFSET_BITS 64
#endif

#ifndef _LARGEFILE64_SOURCE
#define _LARGEFILE64_SOURCE
#endif

#include <stdio.h>
#include <unistd.h>
#include <inttypes.h>
#include <sys/types.h>
#include <limits.h>
#include <fcntl.h>
#include <poll.h>
#include <string.h>
#ifndef IOV_MAX
#define IOV_MAX 1024
#endif

#include <include/pf_file.h>
#include <include/pf_util.h>
#include <include/pf_internal.h>


/*********************************************************************************************
Function Name:  pf_is_nonblock
Description  :  Checking file descriptor is non-blocking or not.
Inputs       :  int fd                             : File descriptor.
                pf_fd_block_e block_type           : File descroptor block type:
                                                     PF_FD_BLOCK    : fd is blocking.
                                                     PF_FD_NONBLOCK : fd is non-blocking.
                                                     PF_FD_UNKNOWN  : fd's block type is unknown.
                                                                      Would sys call fcntl() checking.
Outputs      :  return value                       :   1 : fd is non-blocking.
                                                       0 : fd is blocking.
                                                      -1 : Fail. See errno.
ErrorCodes   :  errno                              : sys call errno from fnctl().
                PF_EINVAL                          : Invalid argument.
History      :
---------------------------------------------------------------------------------------------
Author                 Date                       Comments
lijz                   2011-6-24                  create
**********************************************************************************************/
static inline int pf_is_nonblock(int fd, pf_fd_block_e block_type);

/*********************************************************************************************
Function Name:  pf_block_read_n
Description  :  Like sys call read(), synchronously attempt to read up to count bytes from
                blocking file descriptor fd into the buffer starting at buf,
                until end of file(EOF), timeout or other error.
Inputs       :  int fd                             : File descriptor. Must be blocking fd.
                void* buf                          : Buffer for reading into. Must be NOT NULL.
                int32_t size                       : Buffer size. Must great than zero.
                int32_t timeout                    : Timeout in milliseconds.
                                                     > 0 : Timeout in milliseconds.
                                                       0 : Means return immediately.
                                                     < 0 : Infinite timeout.
Outputs      :  return value                       : > 0 : Success. the number of bytes read return.
                                                       0 : end of file(EOF).
                                                      -1 : Fail or timeout. See errno.
                void* buf                          : readed data filled.
ErrorCodes   :  errno                              : sys call errno from poll() or read().
                PF_ETIMEDOUT                       : timeout.
History      :
---------------------------------------------------------------------------------------------
Author                 Date                       Comments
lijz                   2011-6-24                  create
**********************************************************************************************/
static inline int32_t pf_block_read_n(int fd, void* buf, int32_t size, int32_t timeout);

/*********************************************************************************************
Function Name:  pf_nonblock_read_n
Description  :  Like sys call read(), synchronously attempt to read up to count bytes from
                non-blocking file descriptor fd into the buffer starting at buf,
                until end of file(EOF), timeout or other error.
Inputs       :  int fd                             : File descriptor. Must be non-blocking fd.
                void* buf                          : Buffer for reading into. Must be NOT NULL.
                int32_t size                       : Buffer size. Must great than zero.
                int32_t timeout                    : Timeout in milliseconds.
                                                     > 0 : Timeout in milliseconds.
                                                       0 : Means return immediately.
                                                     < 0 : Infinite timeout.
Outputs      :  return value                       : > 0 : Success. the number of bytes read return.
                                                       0 : end of file(EOF).
                                                      -1 : Fail or timeout. See errno.
                void* buf                          : readed data filled.
ErrorCodes   :  errno                              : sys call errno from read() or poll().
                PF_ETIMEDOUT                       : timeout.
History      :
---------------------------------------------------------------------------------------------
Author                 Date                       Comments
lijz                   2011-6-24                  create
**********************************************************************************************/
static inline int32_t pf_nonblock_read_n(int fd, void* buf, int32_t size, int32_t timeout);

/*********************************************************************************************
Function Name:  pf_block_write_n
Description  :  Like sys call write(), synchronously write up to count bytes from the buffer
                pointed buf to the file referred to by blocking the file descriptor fd,
                until no more data written, timeout or other error.
Inputs       :  int fd                             : File descriptor. Must be blocking fd.
                void* buf                          : Buffer data for writing to fd. Must be NOT NULL.
                int32_t size                       : Buffer size. Must great than zero.
                int32_t timeout                    : Timeout in milliseconds.
                                                     > 0 : Timeout in milliseconds.
                                                       0 : Means return immediately.
                                                     < 0 : Infinite timeout.
Outputs      :  return value                       : > 0 : Success. the number of bytes written return.
                                                       0 : Nothing was written.
                                                      -1 : Fail or timeout. See errno.
ErrorCodes   :  errno                              : sys call errno from write() or poll().
                PF_ETIMEDOUT                       : timeout.
History      :
---------------------------------------------------------------------------------------------
Author                 Date                       Comments
lijz                   2011-6-24                  create
**********************************************************************************************/
static inline int32_t pf_block_write_n(int fd, const void* buf, int32_t size, int32_t timeout);

/*********************************************************************************************
Function Name:  pf_nonblock_write_n
Description  :  Like sys call write(), synchronously write up to count bytes from the buffer
                pointed buf to the file referred to by non-blocking the file descriptor fd,
                until no more data written, timeout or other error.
Inputs       :  int fd                             : File descriptor. Must be non-blocking fd.
                void* buf                          : Buffer data for writing to fd. Must be NOT NULL.
                int32_t size                       : Buffer size. Must great than zero.
                int32_t timeout                    : Timeout in milliseconds.
                                                     > 0 : Timeout in milliseconds.
                                                       0 : Means return immediately.
                                                     < 0 : Infinite timeout.
Outputs      :  return value                       : > 0 : Success. the number of bytes written return.
                                                       0 : Nothing was written.
                                                      -1 : Fail or timeout. See errno.
ErrorCodes   :  errno                              : sys call errno from write() or poll().
                PF_ETIMEDOUT                       : timeout.
History      :
---------------------------------------------------------------------------------------------
Author                 Date                       Comments
lijz                   2011-6-24                  create
**********************************************************************************************/
static inline int32_t pf_nonblock_write_n(int fd, const void* buf, int32_t size, int32_t timeout);

/*********************************************************************************************
Function Name:  pf_block_readv_n
Description  :  Like sys call readv(), synchronously reads iovcnt buffers from the file
                associated with the blocking file descriptor fd into the buffers described by iov,
                until end of file(EOF), timeout or other error.
Inputs       :  int fd                             : File descriptor. Must be blocking fd.
                const struct iovec* iov            : Multiple buffers for reading into. Must be NOT NULL.
                int iovcnt                         : Buffers count. Must great than zero, and limited 1024.
                int32_t timeout                    : Timeout in milliseconds.
                                                     > 0 : Timeout in milliseconds.
                                                       0 : Means return immediately.
                                                     < 0 : Infinite timeout.
Outputs      :  return value                       : > 0 : Success. the number of bytes read return.
                                                       0 : end of file(EOF).
                                                      -1 : Fail or timeout. See errno.
                const struct iovec* iov            : Readed data filled.
ErrorCodes   :  errno                              : sys call errno from read() or poll().
                PF_ETIMEDOUT                       : timeout.
History      :
---------------------------------------------------------------------------------------------
Author                 Date                       Comments
lijz                   2011-6-24                  create
**********************************************************************************************/
static int32_t pf_block_readv_n(int fd, const struct iovec* iov, int iovcnt, int32_t timeout);

/*********************************************************************************************
Function Name:  pf_nonblock_readv_n
Description  :  Like sys call readv(), synchronously reads iovcnt buffers from the file
                associated with the non-blocking file descriptor fd into the buffers described by iov,
                until end of file(EOF), timeout or other error.
Inputs       :  int fd                             : File descriptor. Must be non-blocking fd.
                const struct iovec* iov            : Multiple buffers for reading into. Must be NOT NULL.
                int iovcnt                         : Buffers count. Must great than zero, and limited 1024.
                int32_t timeout                    : Timeout in milliseconds.
                                                     > 0 : Timeout in milliseconds.
                                                       0 : Means return immediately.
                                                     < 0 : Infinite timeout.
Outputs      :  return value                       : > 0 : Success. the number of bytes read return.
                                                       0 : end of file(EOF).
                                                      -1 : Fail or timeout. See errno.
                const struct iovec* iov            : Readed data filled.
ErrorCodes   :  errno                              : sys call errno from read() or poll().
                PF_ETIMEDOUT                       : timeout.
History      :
---------------------------------------------------------------------------------------------
Author                 Date                       Comments
lijz                   2011-6-24                  create
**********************************************************************************************/
static int32_t pf_nonblock_readv_n(int fd, const struct iovec* iov, int iovcnt, int32_t timeout);

/*********************************************************************************************
Function Name:  pf_block_writev_n
Description  :  Like sys call writev(), synchronously writes iovcnt buffers of data described
                by iov to  the  blocking file  associated  with  the  file descriptor fd,
                until no more data written, timeout or other error.
Inputs       :  int fd                             : File descriptor. Must be blocking fd.
                const struct iovec* iov            : Multiple buffers for writing into. Must be NOT NULL.
                int iovcnt                         : Buffers count. Must great than zero, and limited 1024.
                int32_t timeout                    : Timeout in milliseconds.
                                                     > 0 : Timeout in milliseconds.
                                                       0 : Means return immediately.
                                                     < 0 : Infinite timeout.
Outputs      :  return value                       : > 0 : Success. the number of bytes written return.
                                                       0 : Nothing was written.
                                                      -1 : Fail or timeout. See errno.
ErrorCodes   :  errno                              : sys call errno from write() or poll().
                PF_ETIMEDOUT                       : timeout.
History      :
---------------------------------------------------------------------------------------------
Author                 Date                       Comments
lijz                   2011-6-24                  create
**********************************************************************************************/
static int32_t pf_block_writev_n(int fd, const struct iovec* iov, int iovcnt, int32_t timeout);

/*********************************************************************************************
Function Name:  pf_nonblock_writev_n
Description  :  Like sys call writev(), synchronously writes iovcnt buffers of data described
                by iov to  the  non-blocking file  associated  with  the  file descriptor fd,
                until no more data written, timeout or other error.
Inputs       :  int fd                             : File descriptor. Must be non-blocking fd.
                const struct iovec* iov            : Multiple buffers for writing into. Must be NOT NULL.
                int iovcnt                         : Buffers count. Must great than zero, and limited 1024.
                int32_t timeout                    : Timeout in milliseconds.
                                                     > 0 : Timeout in milliseconds.
                                                       0 : Means return immediately.
                                                     < 0 : Infinite timeout.
Outputs      :  return value                       : > 0 : Success. the number of bytes written return.
                                                       0 : Nothing was written.
                                                      -1 : Fail or timeout. See errno.
ErrorCodes   :  errno                              : sys call errno from write() or poll().
                PF_ETIMEDOUT                       : timeout.
History      :
---------------------------------------------------------------------------------------------
Author                 Date                       Comments
lijz                   2011-6-24                  create
**********************************************************************************************/
static int32_t pf_nonblock_writev_n(int fd, const struct iovec* iov, int iovcnt, int32_t timeout);

/*********************************************************************************************/

int64_t pf_fseek(FILE* stream, int64_t offset, int whence)
{
    if(fseeko(stream, offset, whence) != 0)
    {
        return pf_errno();
    }

    return 0;
}

int64_t pf_seek(int fd, int64_t offset, int whence)
{
    if(lseek64(fd, offset, whence) < 0)
    {
        return pf_errno();
    }

    return 0;
}

int64_t pf_ftell(FILE* stream)
{
    return ftello(stream);
}

int64_t pf_tell(int fd)
{
    return lseek64(fd, 0, SEEK_CUR);
}

int pf_set_file_lock(int fd, int64_t offset, int64_t len, pf_file_lock_e lock_mode)
{
    struct flock lock;

    switch(lock_mode)
    {
        case PF_FILE_UNLOCK:
            lock.l_type = F_UNLCK;
            break;
        case PF_FILE_RLOCK:
            lock.l_type = F_RDLCK;
            break;
        case PF_FILE_WLOCK:
            lock.l_type = F_WRLCK;
            break;
        default:
            return PF_EINVAL;
    }

    lock.l_start  = offset;
    lock.l_whence = SEEK_CUR;
    lock.l_len    = len;

    if(fcntl(fd, F_SETLK, &lock) != 0)
    {
        return pf_errno();
    }

    return 0;
}

pf_file_lock_e pf_get_file_lock(int fd, int64_t offset, int64_t len)
{
    pf_file_lock_e ret = PF_FILE_INVALID;
    struct flock lock;

    lock.l_type = F_WRLCK;
    lock.l_start = offset;
    lock.l_whence = SEEK_CUR;
    lock.l_len = len;
    if(fcntl(fd, F_GETLK, &lock) != 0)
    {
        return PF_FILE_INVALID;
    }

    switch(lock.l_type)
    {
        case F_UNLCK:
            ret = PF_FILE_UNLOCK;
            break;
        case F_RDLCK:
            ret = PF_FILE_RLOCK;
            break;
        case F_WRLCK:
            ret = PF_FILE_WLOCK;
            break;
        default: /* should not occur */
            return PF_FILE_INVALID;
    }

    return ret;
}

int pf_set_nonblock(int fd, enum PF_OPT opt)
{
    int flags     = 0;

    flags = fcntl(fd, F_GETFL, 0);
    if(flags < 0)
    {
        return pf_errno();
    }

    switch(opt)
    {
        case PF_ON:
            if(!(flags & O_NONBLOCK) && fcntl(fd, F_SETFL, flags|O_NONBLOCK) != 0)
            {
                return pf_errno();
            }
            break;
        case PF_OFF:
            if((flags & O_NONBLOCK) && fcntl(fd, F_SETFL, flags & (~O_NONBLOCK)) != 0)
            {
                return pf_errno();
            }
            break;
        case PF_INVALID:
        default:
            return PF_EINVAL;

    }

    return 0;
}

int pf_wait_fd(int fd, short events, int32_t timeout)
{
    struct pollfd fds;

    fds.fd      = fd;
    fds.events  = events;
    fds.revents = 0;

    errno = 0;
    do
    {
        int r = poll(&fds, 1, timeout);
        if (r >= 0)
        {
            return fds.revents;
        }
    } while (errno == EINTR);
    return -1;
}

int32_t pf_read_n(int fd, pf_fd_block_e block_type, void* buf, int32_t size, int32_t timeout)
{
    int is_nonblock  = 0;

    assert(buf != NULL);

    is_nonblock = pf_is_nonblock(fd, block_type);
    if(is_nonblock < 0)
    {
        return -1;
    }

    if(is_nonblock)
    {
        return pf_nonblock_read_n(fd, buf, size, timeout);
    }
    else
    {
        return pf_block_read_n(fd, buf, size, timeout);
    }
}

int32_t pf_write_n(int fd, pf_fd_block_e block_type, const void* buf, int32_t size, int32_t timeout)
{
    int is_nonblock  = 0;

    assert(buf != NULL);

    is_nonblock = pf_is_nonblock(fd, block_type);
    if(is_nonblock < 0)
    {
        return -1;
    }

    if(is_nonblock)
    {
        return pf_nonblock_write_n(fd, buf, size, timeout);
    }
    else
    {
        return pf_block_write_n(fd, buf, size, timeout);
    }
}

int32_t pf_readv_n(int fd, pf_fd_block_e block_type, const struct iovec* iov, int iovcnt, int32_t timeout)
{
    int is_nonblock  = 0;

    assert(iov != NULL);
    if(iovcnt <= 0 || iovcnt > IOV_MAX)
    {
        pf_set_errno(PF_EINVAL);
        return -1;
    }

    is_nonblock = pf_is_nonblock(fd, block_type);
    if(is_nonblock < 0)
    {
        return -1;
    }

    if(is_nonblock)
    {
        return pf_nonblock_readv_n(fd, iov, iovcnt, timeout);
    }
    else
    {
        return pf_block_readv_n(fd, iov, iovcnt, timeout);
    }
}

int32_t pf_writev_n(int fd, pf_fd_block_e block_type, const struct iovec* iov, int iovcnt, int32_t timeout)
{
    int is_nonblock  = 0;

    assert(iov != NULL);
    if(iovcnt <= 0 || iovcnt > IOV_MAX)
    {
        pf_set_errno(PF_EINVAL);
        return -1;
    }

    is_nonblock = pf_is_nonblock(fd, block_type);
    if(is_nonblock < 0)
    {
        return -1;
    }

    if(is_nonblock)
    {
        return pf_nonblock_writev_n(fd, iov, iovcnt, timeout);
    }
    else
    {
        return pf_block_writev_n(fd, iov, iovcnt, timeout);
    }
}

/********************************************************************************************/

static inline int pf_is_nonblock(int fd, pf_fd_block_e block_type)
{
    int ret   = -1;
    int flags = 0;

    switch(block_type)
    {
        case PF_FD_BLOCK:
            ret = 0;
            break;
        case PF_FD_NONBLOCK:
            ret = 1;
            break;
        case PF_FD_UNKNOWN:
            flags = fcntl(fd, F_GETFL, 0);
            if(flags < 0)
            {
                ret = -1;
            }
            else if((flags & O_NONBLOCK))
            {
                ret = 1;
            }
            else
            {
                ret = 0;
            }
            break;
        default:
            pf_set_errno(PF_EINVAL);
            ret = -1;
            break;
    }

    return ret;
}

static inline int32_t pf_block_read_n(int fd, void* buf, int32_t size, int32_t timeout)
{
    int exit_loop           = 0;
    int revents             = 0;
    int32_t next_to         = -1;
    int32_t read_size       = 0;
    int32_t total_read_size = 0;
    struct timespec abs_to;

    abs_to = pf_get_abs_time(timeout);
    total_read_size = 0;
    exit_loop = 0;
    do
    {
        next_to = pf_get_rel_time(&abs_to);

        if((timeout > 0 && next_to <= 0))
        {
            pf_set_errno(PF_ETIMEDOUT);
            total_read_size = -1;
            exit_loop = 1;
        }
        else
        {
            revents = pf_wait_fd(fd, POLLIN, (timeout <= 0 ? timeout : next_to));
            switch (revents)
            {
            case POLLIN:
                do
                {
                    read_size = read(fd, buf + total_read_size, size - total_read_size);
                }while(read_size < 0 && errno == EINTR);
                switch (read_size)
                {
                case -1: /* ERROR */
                    total_read_size = -1;
                case 0:  /* EOF */
                    exit_loop = 1;
                    break;
                default:
                    total_read_size += read_size;
                    break;
                }
                break;
            case 0:
                pf_set_errno(PF_ETIMEDOUT);
                total_read_size = -1;
                exit_loop = 1;
                break;
            default: /* other revents or error */
                total_read_size = -1;
                exit_loop = 1;
                break;
            }
        }
    }while(!exit_loop && (total_read_size < size) && timeout != 0);

    return total_read_size;
}

static inline int32_t pf_nonblock_read_n(int fd, void* buf, int32_t size, int32_t timeout)
{
    int exit_loop           = 0;
    int revents             = 0;
    int32_t next_to         = -1;
    int32_t read_size       = 0;
    int32_t total_read_size = 0;
    struct timespec abs_to;

    abs_to = pf_get_abs_time(timeout);
    total_read_size = 0;
    exit_loop = 0;
    do
    {
        read_size = read(fd, buf + total_read_size, size - total_read_size);
        switch (read_size)
        {
        case -1:
            switch(errno)
            {
            case EINTR:
                continue;
                break;
            case EAGAIN:
                next_to = pf_get_rel_time(&abs_to);

                if((timeout == 0) || (timeout > 0 && next_to <= 0))
                {
                    pf_set_errno(PF_ETIMEDOUT);
                    total_read_size = -1;
                    exit_loop = 1;
                }
                else
                {
                    revents = pf_wait_fd(fd, POLLIN, (timeout < 0 ? timeout : next_to));

                    switch (revents)
                    {
                    case POLLIN:
                        continue;
                    case 0:
                        pf_set_errno(PF_ETIMEDOUT);
                        total_read_size = -1;
                        exit_loop = 1;
                        break;
                    default: /* other revents or error */
                        total_read_size = -1;
                        exit_loop = 1;
                        break;
                    }
                }
                break;
            default:
                total_read_size = -1;
                exit_loop = 1;
                break;
            } /* switch(errno) */
            break;
        case 0:
            exit_loop = 1;
            break;
        default:
            total_read_size += read_size;
            break;
        }
    }while(!exit_loop && (total_read_size < size) && timeout != 0);

    return total_read_size;
}

static inline int32_t pf_block_write_n(int fd, const void* buf, int32_t size, int32_t timeout)
{
    int exit_loop            = 0;
    int revents              = 0;
    int32_t next_to          = -1;
    int32_t write_size       = 0;
    int32_t total_write_size = 0;
    struct timespec abs_to;

    abs_to = pf_get_abs_time(timeout);
    total_write_size = 0;
    exit_loop = 0;
    do
    {
        next_to = pf_get_rel_time(&abs_to);

        if((timeout > 0 && next_to <= 0))
        {
            pf_set_errno(PF_ETIMEDOUT);
            total_write_size = -1;
            exit_loop = 1;
        }
        else
        {
            revents = pf_wait_fd(fd, POLLOUT, (timeout <= 0 ? timeout : next_to));

            if(revents == POLLOUT)
            {
                do
                {
                    write_size = write(fd, buf + total_write_size, size - total_write_size);
                }while(write_size < 0 && errno == EINTR);
                if(write_size > 0)
                {
                    total_write_size += write_size;
                }
                else if(write_size == 0) /* nothing was written */
                {
                    exit_loop = 1;
                }
                else /* write_size < 0 */
                {
                    total_write_size = -1;
                    exit_loop = 1;
                }
            }
            else if(revents == 0)
            {
                pf_set_errno(PF_ETIMEDOUT);
                total_write_size = -1;
                exit_loop = 1;
            }
            else /* other revents or error */
            {
                total_write_size = -1;
                exit_loop = 1;
            }
        }
    }while(!exit_loop && (total_write_size < size) && timeout != 0);

    return total_write_size;
}

static inline int32_t pf_nonblock_write_n(int fd, const void* buf, int32_t size, int32_t timeout)
{
    int exit_loop            = 0;
    int revents              = 0;
    int32_t next_to          = -1;
    int32_t write_size       = 0;
    int32_t total_write_size = 0;
    struct timespec abs_to;

    abs_to = pf_get_abs_time(timeout);
    total_write_size = 0;
    exit_loop = 0;
    do
    {
        write_size = write(fd, buf + total_write_size, size - total_write_size);
        if(write_size > 0)
        {
            total_write_size += write_size;
        }
        else if(write_size == 0) /* nothing was writen */
        {
            exit_loop = 1;
        }
        else /* write_size < 0 */
        {
            switch(errno)
            {
                case EINTR:
                    continue;
                    break;
                case EAGAIN:
                    next_to = pf_get_rel_time(&abs_to);

                    if((timeout == 0) || (timeout > 0 && next_to <= 0))
                    {
                        pf_set_errno(PF_ETIMEDOUT);
                        total_write_size = -1;
                        exit_loop = 1;
                    }
                    else
                    {
                        revents = pf_wait_fd(fd, POLLOUT, (timeout < 0 ? timeout : next_to));

                        if(revents == POLLOUT)
                        {
                            continue;
                        }
                        else if(revents == 0)
                        {
                            pf_set_errno(PF_ETIMEDOUT);
                            total_write_size = -1;
                            exit_loop = 1;
                        }
                        else /* other revents or error */
                        {
                            total_write_size = -1;
                            exit_loop = 1;
                        }
                    }
                    break;
                default:
                    total_write_size = -1;
                    exit_loop = 1;
                    break;
            } /* switch(errno) */
        } /* write_size < 0 */

    }while(!exit_loop && (total_write_size < size) && timeout != 0);

    return total_write_size;
}

static int32_t pf_block_readv_n(int fd, const struct iovec* iov, int iovcnt, int32_t timeout)
{
    int exit_loop                   = 0;
    int revents                     = 0;
    int32_t next_to                 = -1;
    register ssize_t read_size      = 0;
    int32_t total_read_size         = 0;
    struct iovec iovc[iovcnt];
    register struct iovec* iovc_ptr = NULL;
    int iovc_cnt                    = 0;
    struct timespec abs_to;

    memcpy(iovc, iov, sizeof(struct iovec) * iovcnt);
    iovc_ptr = iovc;
    iovc_cnt = iovcnt;
    abs_to = pf_get_abs_time(timeout);
    total_read_size = 0;
    exit_loop = 0;
    do
    {
        next_to = pf_get_rel_time(&abs_to);

        if((timeout > 0 && next_to <= 0))
        {
            pf_set_errno(PF_ETIMEDOUT);
            total_read_size = -1;
            exit_loop = 1;
        }
        else
        {
            revents = pf_wait_fd(fd, POLLIN, (timeout <= 0 ? timeout : next_to));

            if(revents == POLLIN)
            {
                do
                {
                    read_size = readv(fd, iovc_ptr, iovc_cnt);
                }while(read_size < 0 && errno == EINTR);
                if(read_size > 0)
                {
                    total_read_size += read_size;
                    while(read_size > 0 && iovc_cnt > 0)
                    {
                        if(iovc_ptr->iov_len <= (size_t)read_size)
                        {
                            read_size -= iovc_ptr->iov_len;
                            iovc_ptr++;
                            iovc_cnt--;
                        }
                        else
                        {
                            iovc_ptr->iov_base += read_size;
                            iovc_ptr->iov_len -= read_size;
                            read_size = 0;
                        }
                    } /* while(read_size > 0 && iovc_cnt > 0) */
                    if(iovc_cnt <= 0) /* read all done */
                    {
                        exit_loop = 1;
                    }
                }
                else if(read_size == 0) /* EOF */
                {
                    exit_loop = 1;
                }
                else /* read_size < 0 */
                {
                    total_read_size = -1;
                    exit_loop = 1;
                }
            }
            else if(revents == 0)
            {
                pf_set_errno(PF_ETIMEDOUT);
                total_read_size = -1;
                exit_loop = 1;
            }
            else /* other revents or error */
            {
                total_read_size = -1;
                exit_loop = 1;
            }
        }
    }while(!exit_loop && timeout != 0);

    return total_read_size;
}

static int32_t pf_nonblock_readv_n(int fd, const struct iovec* iov, int iovcnt, int32_t timeout)
{
    int exit_loop                   = 0;
    int revents                     = 0;
    int32_t next_to                 = -1;
    register ssize_t read_size      = 0;
    int32_t total_read_size         = 0;
    struct iovec iovc[iovcnt];
    register struct iovec* iovc_ptr = NULL;
    int iovc_cnt                    = 0;
    struct timespec abs_to;

    memcpy(iovc, iov, sizeof(struct iovec) * iovcnt);
    iovc_ptr = iovc;
    iovc_cnt = iovcnt;
    abs_to = pf_get_abs_time(timeout);
    total_read_size = 0;
    exit_loop = 0;
    do
    {
        read_size = readv(fd, iovc_ptr, iovc_cnt);
        if(read_size > 0)
        {
            total_read_size += read_size;
            while(read_size > 0 && iovc_cnt > 0)
            {
                if(iovc_ptr->iov_len <= (size_t)read_size)
                {
                    read_size -= iovc_ptr->iov_len;
                    iovc_ptr++;
                    iovc_cnt--;
                }
                else
                {
                    iovc_ptr->iov_base += read_size;
                    iovc_ptr->iov_len -= read_size;
                    read_size = 0;
                }
            } /* while(read_size > 0 && iovc_cnt > 0) */
            if(iovc_cnt <= 0) /* read all done */
            {
                exit_loop = 1;
            }
        }
        else if(read_size == 0) /* EOF */
        {
            exit_loop = 1;
        }
        else /* read_size < 0 */
        {
            switch(errno)
            {
                case EINTR:
                    continue;
                    break;
                case EAGAIN:
                    next_to = pf_get_rel_time(&abs_to);

                    if((timeout == 0) || (timeout > 0 && next_to <= 0))
                    {
                        pf_set_errno(PF_ETIMEDOUT);
                        total_read_size = -1;
                        exit_loop = 1;
                    }
                    else
                    {
                        revents = pf_wait_fd(fd, POLLIN, (timeout < 0 ? timeout : next_to));

                        if(revents == POLLIN)
                        {
                            continue;
                        }
                        else if(revents == 0)
                        {
                            pf_set_errno(PF_ETIMEDOUT);
                            total_read_size = -1;
                            exit_loop = 1;
                        }
                        else /* other revents or error */
                        {
                            total_read_size = -1;
                            exit_loop = 1;
                        }
                    }
                    break;
                default:
                    total_read_size = -1;
                    exit_loop = 1;
                    break;
            } /* switch(errno) */
        } /* read_size < 0 */

    }while(!exit_loop && timeout != 0);

    return total_read_size;
}

static int32_t pf_block_writev_n(int fd, const struct iovec* iov, int iovcnt, int32_t timeout)
{
    int exit_loop                   = 0;
    int revents                     = 0;
    int32_t next_to                 = -1;
    register ssize_t write_size     = 0;
    int32_t total_write_size        = 0;
    struct iovec iovc[iovcnt];
    register struct iovec* iovc_ptr = NULL;
    int iovc_cnt                    = 0;
    struct timespec abs_to;

    memcpy(iovc, iov, sizeof(struct iovec) * iovcnt);
    iovc_ptr = iovc;
    iovc_cnt = iovcnt;
    abs_to = pf_get_abs_time(timeout);
    total_write_size = 0;
    exit_loop = 0;
    do
    {
        next_to = pf_get_rel_time(&abs_to);

        if((timeout > 0 && next_to <= 0))
        {
            pf_set_errno(PF_ETIMEDOUT);
            total_write_size = -1;
            exit_loop = 1;
        }
        else
        {
            revents = pf_wait_fd(fd, POLLOUT, (timeout <= 0 ? timeout : next_to));

            if(revents == POLLOUT)
            {
                do
                {
                    write_size = writev(fd, iovc_ptr, iovc_cnt);
                }while(write_size < 0 && errno == EINTR);
                if(write_size > 0)
                {
                    total_write_size += write_size;
                    while(write_size > 0 && iovc_cnt > 0)
                    {
                        if(iovc_ptr->iov_len <= (size_t)write_size)
                        {
                            write_size -= iovc_ptr->iov_len;
                            iovc_ptr++;
                            iovc_cnt--;
                        }
                        else
                        {
                            iovc_ptr->iov_base += write_size;
                            iovc_ptr->iov_len -= write_size;
                            write_size = 0;
                        }
                    } /* while(write_size > 0 && iovc_cnt > 0) */
                    if(iovc_cnt <= 0) /* write all done */
                    {
                        exit_loop = 1;
                    }
                }
                else if(write_size == 0) /* nothing was written */
                {
                    exit_loop = 1;
                }
                else /* write_size < 0 */
                {
                    total_write_size = -1;
                    exit_loop = 1;
                }
            }
            else if(revents == 0)
            {
                pf_set_errno(PF_ETIMEDOUT);
                total_write_size = -1;
                exit_loop = 1;
            }
            else /* other revents or error */
            {
                total_write_size = -1;
                exit_loop = 1;
            }
        }
    }while(!exit_loop && timeout != 0);

    return total_write_size;
}

static int32_t pf_nonblock_writev_n(int fd, const struct iovec* iov, int iovcnt, int32_t timeout)
{
    int exit_loop                   = 0;
    int revents                     = 0;
    int32_t next_to                 = -1;
    register ssize_t write_size     = 0;
    int32_t total_write_size        = 0;
    struct iovec iovc[iovcnt];
    register struct iovec* iovc_ptr = NULL;
    int iovc_cnt                    = 0;
    struct timespec abs_to;

    memcpy(iovc, iov, sizeof(struct iovec) * iovcnt);
    iovc_ptr = iovc;
    iovc_cnt = iovcnt;
    abs_to = pf_get_abs_time(timeout);
    total_write_size = 0;
    exit_loop = 0;
    do
    {
        write_size = writev(fd, iovc_ptr, iovc_cnt);
        if(write_size > 0)
        {
            total_write_size += write_size;
            while(write_size > 0 && iovc_cnt > 0)
            {
                if(iovc_ptr->iov_len <= (size_t)write_size)
                {
                    write_size -= iovc_ptr->iov_len;
                    iovc_ptr++;
                    iovc_cnt--;
                }
                else
                {
                    iovc_ptr->iov_base += write_size;
                    iovc_ptr->iov_len -= write_size;
                    write_size = 0;
                }
            } /* while(write_size > 0 && iovc_cnt > 0)*/
            if(iovc_cnt <= 0) /* write all done */
            {
                exit_loop = 1;
            }
        }
        else if(write_size == 0) /* nothing was written */
        {
            exit_loop = 1;
        }
        else /* write_size < 0 */
        {
            switch(errno)
            {
                case EINTR:
                    continue;
                    break;
                case EAGAIN:
                    next_to = pf_get_rel_time(&abs_to);

                    if((timeout == 0) || (timeout > 0 && next_to <= 0))
                    {
                        pf_set_errno(PF_ETIMEDOUT);
                        total_write_size = -1;
                        exit_loop = 1;
                    }
                    else
                    {
                        revents = pf_wait_fd(fd, POLLOUT, (timeout < 0 ? timeout : next_to));

                        if(revents == POLLOUT)
                        {
                            continue;
                        }
                        else if(revents == 0)
                        {
                            pf_set_errno(PF_ETIMEDOUT);
                            total_write_size = -1;
                            exit_loop = 1;
                        }
                        else /* other revents or error */
                        {
                            total_write_size = -1;
                            exit_loop = 1;
                        }
                    }
                    break;
                default:
                    total_write_size = -1;
                    exit_loop = 1;
                    break;
            } /* switch(errno) */
        } /* write_size < 0 */

    }while(!exit_loop && timeout != 0);

    return total_write_size;
}

